package com.kelvem.saas.workbanch.core.manager.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.kelvem.saas.workbanch.core.SaasConstant;
import com.kelvem.saas.workbanch.core.base.BaseCriteria;
import com.kelvem.saas.workbanch.core.base.BaseService;
import com.kelvem.saas.workbanch.core.base.Page;
import com.kelvem.saas.workbanch.core.exception.SaasAssert;
import com.kelvem.saas.workbanch.core.exception.SaasException;
import com.kelvem.saas.workbanch.core.manager.dao.BizPageDao;
import com.kelvem.saas.workbanch.core.manager.dao.MetaTableDao;
import com.kelvem.saas.workbanch.core.manager.model.BizPageEntity;
import com.kelvem.saas.workbanch.core.manager.model.MetaTableActionEntity;
import com.kelvem.saas.workbanch.core.manager.model.MetaTableColumnEntity;
import com.kelvem.saas.workbanch.core.manager.model.MetaTableEntity;
import com.kelvem.saas.workbanch.core.manager.request.MetaTableQueryVo;
import com.kelvem.saas.workbanch.core.utils.DateUtil;
import com.kelvem.saas.workbanch.fsm.dao.BaseDao;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 实体表Service
 *
 * @author kelvem
 * @version 1.0
 */
@Service
@Slf4j
public class MetaTableService extends BaseService<MetaTableEntity, MetaTableQueryVo> {

    @Resource
    private MetaTableDao metaTableDao;
    
    @Resource
    private MetaTableColumnService metaTableColumnService;
    
    @Resource
    private MetaTableActionService metaTableActionService;

    // todo 为了解决循环依赖的问题, 临时处理
    @Resource
    private BizPageDao bizPageDao;


    /**
     * 增加实体表
     *
     * @param metaTable 实体表信息
     * @return Long 主键
     */
    @Transactional(rollbackFor = Exception.class)
    public Long addMetaTable(MetaTableEntity metaTable) {
        
        log.info("MetaTableService:addMetaTable:start, metaTable=【{}】", metaTable);
        SaasAssert.notNull(metaTable);
        
        try {
            if (metaTable.getCreateTime() == null) {
                metaTable.setCreateTime(DateUtil.now());
            }
            if (metaTable.getUpdateTime() == null) {
                metaTable.setUpdateTime(DateUtil.now());
            }
            
            metaTableDao.insert(metaTable);
            Long metaTableId = metaTable.getId();
            log.info("MetaTableService:addMetaTable:end, metaTableId={}", metaTableId);
    
            if (metaTable.getTableEnName().startsWith("yy_")) {
                metaTable.setTableEnName(metaTable.getTableEnName().replace("yy_", "zz_" + metaTableId + "_"));
            } else {
                metaTable.setTableEnName("zz_" + metaTableId + "_" + metaTable.getTableEnName());
            }
            metaTableDao.updateById(metaTable);


            /**
             * copy parent metaTable column & action
             */
            if (isNotEmpty(metaTable.getParentMetaTableId())) {
                MetaTableEntity parentMetaTable = this.getMetaTableById(metaTable.getParentMetaTableId());
                if (isNotEmpty(parentMetaTable)) {
                    // copy metaTableColumn
                    List<MetaTableColumnEntity> metaTableColumnList = parentMetaTable.getMetaTableColumnList();
                    metaTableColumnService.copyMetaTableColumn(metaTableColumnList, metaTable.getId());

                    // copy metaTableAction
                    List<MetaTableActionEntity> metaTableActionList = parentMetaTable.getMetaTableActionList();
                    metaTableActionService.copyMetaTableAction(metaTableActionList, metaTable.getId());
                } else {
                    log.warn("继承父表创建表格时, 父表不存在, parentMetaTableId={}", metaTable.getParentMetaTableId());
                }
            }

            return metaTable.getId();
        } catch (Exception e) {
            String msg = String.format("MetaTableService:addMetaTable:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 修改实体表
     *
     * @param metaTable 实体表信息
     * @return 更新记录数
     */
    @Transactional(rollbackFor = Exception.class)
    public int updateMetaTable(MetaTableEntity metaTable) {
        
        log.info("MetaTableService:updateMetaTable:start, metaTable=【{}】", metaTable);
        SaasAssert.notNull(metaTable);
        SaasAssert.notNull(metaTable.getId());

        try {
            int count = metaTableDao.updateById(metaTable);
            log.info("MetaTableService:updateMetaTable:end, count={}", count);
            return count;
        } catch (Exception e) {
            String msg = String.format("MetaTableService:updateMetaTable:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 删除实体表
     *
     * @param metaTableId 实体表id
     * @return 删除记录数
     */
    @Transactional(rollbackFor = Exception.class)
    public int deleteMetaTable(Long metaTableId) {

        log.info("MetaTableService:deleteMetaTable:start, metaTableId={}", metaTableId);
        SaasAssert.notNull(metaTableId);
        
        try {
            // drop表(目前仅检查, 不真实删除)
            MetaTableEntity metaTable = this.getMetaTableById(metaTableId);
            this.dropMetaTable(metaTableId, metaTable.getTableEnName());

            // metaTableColumn
            metaTableColumnService.deleteByParentMetaTableId(metaTableId);
    
            // metaTableAction
            metaTableActionService.deleteByParentMetaTableId(metaTableId);
    
            // metaTable
            int count = metaTableDao.deleteById(metaTableId);
            
            log.info("MetaTableService:deleteMetaTable:end, count={}", count);
            return count;
        } catch (Exception e) {
            String msg = String.format("MetaTableService:deleteMetaTable:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(e.getMessage());
        }
    }
    
    /**
     * 查询实体表分页数据
     *
     * @param metaTableQueryVo 查询用
     * @return Page<MetaTableDto>
     */
    public Page<MetaTableEntity> queryMetaTablePage(MetaTableQueryVo metaTableQueryVo) {
        
        log.info("MetaTableService:queryMetaTablePage:start, metaTableQueryVo=【{}】", metaTableQueryVo);
        SaasAssert.notNull(metaTableQueryVo);
        
        try {
            Page<MetaTableEntity> page = super.queryPage(metaTableQueryVo);
            log.info("MetaTableService:queryMetaTablePage:end, page.size={}", page.getRecords().size());
            return page;
        } catch (Exception e) {
            String msg = String.format("MetaTableService:queryMetaTablePage:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 查询实体表列表数据
     *
     * @param metaTableQueryVo 查询用
     * @return List<MetaTable>
     */
    public List<MetaTableEntity> queryMetaTableList(MetaTableQueryVo metaTableQueryVo) {
        
        log.info("MetaTableService:queryMetaTableList:start, metaTableQueryVo=【{}】", metaTableQueryVo);
        SaasAssert.notNull(metaTableQueryVo);
        
        try {
            // table
            List<MetaTableEntity> list = super.queryList(metaTableQueryVo);
            for (MetaTableEntity metaTable : list) {
                // table column
                List<MetaTableColumnEntity> metaTableColumnList = this.metaTableColumnService.queryMetaTableColumnList(metaTable.getId());
                metaTable.setMetaTableColumnList(metaTableColumnList);

                // table event
                List<MetaTableActionEntity> metaTableActionList = this.metaTableActionService.queryMetaTableActionList(metaTable.getId());
                metaTable.setMetaTableActionList(metaTableActionList);
            }
            log.info("MetaTableService:queryMetaTableList:end, list.size={}", list.size());
            return list;
        } catch (Exception e) {
            String msg = String.format("MetaTableService:queryMetaTableList:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 根据id查询实体表信息
     *
     * @param metaTableId 实体表id
     * @return MetaTable
     */
    public MetaTableEntity getMetaTableById(Long metaTableId) {

        log.info("MetaTableService:getMetaTableById:start, metaTableId={}", metaTableId);
        SaasAssert.notNull(metaTableId);
        
        try {
            MetaTableEntity metaTable = metaTableDao.getMetaTableById(metaTableId);
            log.info("MetaTableService:getMetaTableById:end, metaTableInfo=【{}】", metaTable);
            return metaTable;
        } catch (Exception e) {
            String msg = String.format("MetaTableService:getMetaTableById:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 构建查询用Criteria
     * 基类的queryPage, queryList方法使用
     *
     * @param queryVo 查询用
     * @return BaseCriteria
     */
    @Override
    public BaseCriteria<MetaTableEntity> buildQueryCriteria(MetaTableQueryVo queryVo) {
        BaseCriteria<MetaTableEntity> criteria = new BaseCriteria<>();
        criteria.orderByDesc("id");

        // 主键
        Long id = queryVo.getId();
        if (super.isNotEmpty(id)) {
            criteria.andEqualTo("id", queryVo.getId());
        }

        // 创建时间
        Date startCreateTime = queryVo.getStartCreateTime();
        if(super.isNotEmpty(startCreateTime)) {
            criteria.andGreaterThanOrEqualTo("createTime", startCreateTime);
        }
        Date endCreateTime = queryVo.getEndCreateTime();
        if(super.isNotEmpty(endCreateTime)) {
            criteria.andLessThanOrEqualTo("createTime", endCreateTime);
        }

        // 表名
        String tableEnName = queryVo.getTableEnName();
        if (super.isNotEmpty(tableEnName)) {
            criteria.andEqualTo("tableEnName", tableEnName);
        }

        // 实体表类型, entity:实体; table:表
        String tableType = queryVo.getTableType();
        if (super.isNotEmpty(tableType)) {
            criteria.andEqualTo("tableType", tableType);
        }

        // 实体表来源, system:系统; manual:人工; copy:拷贝
        String tableSource = queryVo.getTableSource();
        if (super.isNotEmpty(tableSource)) {
            criteria.andEqualTo("tableSource", tableSource);
        }

        // 实体名称
        String entityName = queryVo.getEntityName();
        if (super.isNotEmpty(entityName)) {
            criteria.andEqualTo("entityName", entityName);
        }

        // 实体表状态, pending:新建; created:表创建; fix:固定
        String state = queryVo.getState();
        if (super.isNotEmpty(state)) {
            criteria.andEqualTo("state", state);
        }

        // 父表id
        Long parentMetaTableId = queryVo.getParentMetaTableId();
        if (super.isNotEmpty(parentMetaTableId)) {
            criteria.andEqualTo("parentMetaTableId", parentMetaTableId);
        }

        // 创建人
        String createUid = queryVo.getCreateUid();
        if (super.isNotEmpty(createUid)) {
            criteria.andEqualTo("createUid", createUid);
        }

        // 更新人
        String updateUid = queryVo.getUpdateUid();
        if (super.isNotEmpty(updateUid)) {
            criteria.andEqualTo("updateUid", updateUid);
        }

        // stateList
        List<String> stateList = queryVo.getStateList();
        if (super.isNotEmpty(stateList)) {
            criteria.andIn("state", stateList);
        }

        // ids
        List<Long> ids = queryVo.getIds();
        if (super.isNotEmpty(ids)) {
            criteria.andIn("id", ids);
        }

        return criteria;
    }

    @Override
    public BaseDao<MetaTableEntity> getDao() {
        return this.metaTableDao;
    }
    
    
    /**
     * 拷贝实体表
     *
     * @param id 被拷贝的实体表id
     * @return Long 拷贝生成的实体表id
     */
    @Transactional(rollbackFor = Exception.class)
    public Long copyMetaTable(Long id) {
        
        log.info("MetaTableService:copyMetaTable:start, sourceId=【{}】", id);
        SaasAssert.notNull(id);
        
        try {
            /**
             * copy metaTable
             */
            MetaTableEntity sourceMetaTable = this.getMetaTableById(id);
            MetaTableEntity targetMetaTable = new MetaTableEntity();
            BeanUtils.copyProperties(sourceMetaTable, targetMetaTable);
    
            targetMetaTable.setId(null);
            targetMetaTable.setCreateTime(DateUtil.now());
            targetMetaTable.setUpdateTime(DateUtil.now());
            // targetMetaTable.setParentTableId(sourceMetaTable.getId());
            targetMetaTable.setTableType("table");
            targetMetaTable.setTableSource("copy");
            targetMetaTable.setState("pending");

            targetMetaTable.setParentMetaTableId(id);
            
            metaTableDao.insert(targetMetaTable);
            Long targetMetaTableId = targetMetaTable.getId();
            log.info("MetaTableService:copyMetaTable:end, targetId={}", targetMetaTableId);
    
            /**
             * copy metaTableColumn
             */
            List<MetaTableColumnEntity> metaTableColumnList = sourceMetaTable.getMetaTableColumnList();
            metaTableColumnService.copyMetaTableColumn(metaTableColumnList, targetMetaTableId);
    
            /**
             * copy metaTableAction
             */
            List<MetaTableActionEntity> metaTableActionList = sourceMetaTable.getMetaTableActionList();
            metaTableActionService.copyMetaTableAction(metaTableActionList, targetMetaTableId);

            /**
             * update metaTable's tableEnName
             */
            if (targetMetaTable.getTableEnName().startsWith("yy_")) {
                targetMetaTable.setTableEnName(targetMetaTable.getTableEnName().replace("yy_", "zz_" + targetMetaTableId + "_"));
            } else {
                targetMetaTable.setTableEnName("zz_" + targetMetaTableId + "_" + targetMetaTable.getTableEnName());
            }
            metaTableDao.updateById(targetMetaTable);
            
            return targetMetaTableId;
        } catch (Exception e) {
            String msg = String.format("MetaTableService:copyMetaTable:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 删除实体表(目前仅检查, 不真实删除)
     *
     * @param metaTableName 实体表名
     */
    public void dropMetaTable(Long metaTableId, String metaTableName) {

        log.info("MetaTableService:dropMetaTable:start, metaTableId={}, metaTableName={}", metaTableId, metaTableName);
        SaasAssert.notNull(metaTableName);

        try {
            // 检查涉及的页面
            LambdaQueryWrapper<BizPageEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(BizPageEntity::getMetaTableId, metaTableId);
            List<BizPageEntity> bizPageList = bizPageDao.selectList(queryWrapper);
            if (!bizPageList.isEmpty()) {
                throw new SaasException("删除" + metaTableName + "表时, 需要先删除涉及的页面(" + bizPageList.size() + "个)");
            }

            // drop表
//            metaTableDao.dropMetaTable(metaTableName);

            log.info("MetaTableService:dropMetaTable:end");
        } catch (Exception e) {
            String msg = String.format("MetaTableService:dropMetaTable:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(e.getMessage());
        }

    }

    /**
     * 创建实体表
     *
     * @param metaTableId 实体表id
     */
    public void createMetaTable(Long metaTableId) {
        
        log.info("MetaTableService:createMetaTable:start, metaTableId={}", metaTableId);
        SaasAssert.notNull(metaTableId);
        
        try {
            
//            "CREATE TABLE `biz_page1` (\n" +
//            "  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '实体业务id',\n" +
//            "  `meta_table_id` bigint(20) DEFAULT NULL COMMENT '实体表id',\n" +
//            "  `meta_table_name` varchar(128) DEFAULT '' COMMENT '实体表名',\n" +
//            "\n" +
//            "  `menu1` varchar(32) DEFAULT '' COMMENT '一级菜单',\n" +
//            "  `menu2` varchar(32) DEFAULT '' COMMENT '二级菜单',\n" +
//            "  `template_type` varchar(32) DEFAULT '' COMMENT '模板类型',\n" +
//            "\n" +
//            "  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n" +
//            "  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',\n" +
//            "  `create_uid` varchar(32) DEFAULT '' COMMENT '创建人',\n" +
//            "  `update_uid` varchar(32) DEFAULT '' COMMENT '更新人',\n" +
//            "  `memo` varchar(1024) DEFAULT '' COMMENT '备注',\n" +
//            "  PRIMARY KEY (`id`)\n" +
//            ") ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8mb4 COMMENT '实体业务'\n" +
//            ";"
    
            MetaTableEntity metaTable = this.getMetaTableById(metaTableId);

            /**
             * drop table if exists
             * 目前仅检查, 不真实删除
             */
            dropMetaTable(metaTableId, metaTable.getTableEnName());

            /**
             * create table
             */
            StringBuilder sb = new StringBuilder();
            sb.append("CREATE TABLE `").append(metaTable.getTableEnName()).append("` ( \n");
            sb.append("`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', \n");
            
            List<MetaTableColumnEntity> metaTableColumnList = metaTable.getMetaTableColumnList();
            for (MetaTableColumnEntity metaTableColumn:
                    metaTableColumnList) {
                if (metaTableColumn.getEnName().equalsIgnoreCase("id")) {
                    continue;
                }
                
                sb.append("`").append(metaTableColumn.getEnName()).append("` ").append(metaTableColumn.getDbType());
                
                int colSize = metaTableColumnService.calColSize(metaTableColumn);
                if (colSize > 0) {
                    sb.append("(").append(colSize).append(") ");
                }

                if (metaTableColumn.getRequireFlag().equals(SaasConstant.FLAG_YES)) {
                    sb.append(" NOT NULL ");
                }
                if (metaTableColumn.getEnName().equalsIgnoreCase("update_time")) {
                    sb.append(" DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ");
                } else if (metaTableColumn.getEnName().equalsIgnoreCase("create_time")) {
                    sb.append(" DEFAULT CURRENT_TIMESTAMP ");
                }
                sb.append(" COMMENT '").append(metaTableColumn.getChName()).append("', \n");
            }
            sb.append(" PRIMARY KEY (`id`) \n");
            sb.append(" ) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8mb4 COMMENT '").append(metaTable.getTableChName()).append("' \n");
            
            metaTableDao.createMetaTable(sb.toString());
    
            /**
             * 更新记录状态
             */
            metaTable.setState("created");
            metaTableDao.updateById(metaTable);
            
            log.info("MetaTableService:createMetaTable:end");
        } catch (Exception e) {
            String msg = String.format("MetaTableService:createMetaTable:error, %s", e.getMessage());
            log.error(msg, e);
            throw new SaasException(msg);
        }
    }

    /**
     * 导入实体表
     *
     * @param metaTable 实体表
     * @return Long 生成的实体表id
     */
    @Transactional(rollbackFor = Exception.class)
    public Long importMetaTable(MetaTableEntity metaTable) {
        SaasAssert.notNull(metaTable);
        SaasAssert.notNull(metaTable.getTableEnName());

        log.debug("MetaTableController:importTable:start, metaTable=【{}】", metaTable);

        // 校验表是否已存在
        MetaTableQueryVo metaTableQueryVo = MetaTableQueryVo.builder().tableEnName(metaTable.getTableEnName()).build();
        List<MetaTableEntity> buf = this.queryMetaTableList(metaTableQueryVo);
        if (!buf.isEmpty()) {
            throw new SaasException(metaTable.getTableEnName() + "表已存在");
        }

        /**
         * MetaTableEntity
         */
        MetaTableEntity importTable = new MetaTableEntity();
        importTable.setId(null);
        importTable.setCreateTime(DateUtil.now());
        importTable.setUpdateTime(DateUtil.now());
        importTable.setMemo("");
        importTable.setTableEnName(metaTable.getTableEnName());
        importTable.setTableType("entity");
        importTable.setTableSource("import");
        importTable.setTableChName(metaTable.getTableChName());
        importTable.setEntityName(metaTable.getTableChName());
        importTable.setState("fix");

        metaTableDao.insert(importTable);
        Long importTableId = importTable.getId();

        /**
         * metaTableColumn
         */
        metaTableColumnService.importTableColumn(metaTable, importTableId);

        /**
         * metaTableAction
         */
        metaTableActionService.importTableEvent(importTableId);

        log.info("MetaTableService:importTable:end, importTable.id={}", importTableId);
        return importTableId;
    }
}
